home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / move.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-25  |  62.2 KB  |  2,752 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9. /*
  10.  * move.c: Functions for moving the cursor and scrolling text.
  11.  *
  12.  * There are two ways to move the cursor:
  13.  * 1. Move the cursor directly, the text is scrolled to keep the cursor in the
  14.  *    window.
  15.  * 2. Scroll the text, the cursor is moved into the text visible in the
  16.  *    window.
  17.  * The 'scrolloff' option makes this a bit complicated.
  18.  */
  19.  
  20. #include "vim.h"
  21.  
  22. static void comp_botline __ARGS((win_T *wp));
  23. static int check_top_offset __ARGS((void));
  24. static void curs_rows __ARGS((win_T *wp, int do_botline));
  25. static void validate_botline_win __ARGS((win_T *wp));
  26. static void validate_cheight __ARGS((void));
  27.  
  28. typedef struct
  29. {
  30.     linenr_T        lnum;    /* line number */
  31. #ifdef FEAT_DIFF
  32.     int            fill;    /* filler lines */
  33. #endif
  34.     int            height;    /* height of added line */
  35. } lineoff_T;
  36.  
  37. static void topline_back __ARGS((lineoff_T *lp));
  38. static void botline_forw __ARGS((lineoff_T *lp));
  39. #ifdef FEAT_DIFF
  40. static void botline_topline __ARGS((lineoff_T *lp));
  41. static void topline_botline __ARGS((lineoff_T *lp));
  42. static void max_topfill __ARGS((void));
  43. #endif
  44.  
  45. /*
  46.  * Compute wp->w_botline for the current wp->w_topline.  Can be called after
  47.  * wp->w_topline changed.
  48.  */
  49.     static void
  50. comp_botline(wp)
  51.     win_T    *wp;
  52. {
  53.     int        n;
  54.     linenr_T    lnum;
  55.     int        done;
  56. #ifdef FEAT_FOLDING
  57.     linenr_T    last;
  58.     int        folded;
  59. #endif
  60.  
  61.     /*
  62.      * If w_cline_row is valid, start there.
  63.      * Otherwise have to start at w_topline.
  64.      */
  65.     check_cursor_moved(wp);
  66.     if (wp->w_valid & VALID_CROW)
  67.     {
  68.     lnum = wp->w_cursor.lnum;
  69.     done = wp->w_cline_row;
  70.     }
  71.     else
  72.     {
  73.     lnum = wp->w_topline;
  74.     done = 0;
  75.     }
  76.  
  77.     for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
  78.     {
  79. #ifdef FEAT_FOLDING
  80.     last = lnum;
  81.     folded = FALSE;
  82.     if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL))
  83.     {
  84.         n = 1;
  85.         folded = TRUE;
  86.     }
  87.     else
  88. #endif
  89. #ifdef FEAT_DIFF
  90.         if (lnum == wp->w_topline)
  91.         n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill;
  92.         else
  93. #endif
  94.         n = plines_win(wp, lnum, TRUE);
  95.     if (
  96. #ifdef FEAT_FOLDING
  97.         lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum
  98. #else
  99.         lnum == wp->w_cursor.lnum
  100. #endif
  101.        )
  102.     {
  103.         wp->w_cline_row = done;
  104.         wp->w_cline_height = n;
  105. #ifdef FEAT_FOLDING
  106.         wp->w_cline_folded = folded;
  107. #endif
  108.         wp->w_valid |= (VALID_CROW|VALID_CHEIGHT);
  109.     }
  110.     if (done + n > wp->w_height)
  111.         break;
  112.     done += n;
  113. #ifdef FEAT_FOLDING
  114.     lnum = last;
  115. #endif
  116.     }
  117.  
  118.     /* wp->w_botline is the line that is just below the window */
  119.     wp->w_botline = lnum;
  120.     wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  121.  
  122.     set_empty_rows(wp, done);
  123. }
  124.  
  125. /*
  126.  * Update curwin->w_topline and redraw if necessary.
  127.  * Used to update the screen before printing a message.
  128.  */
  129.     void
  130. update_topline_redraw()
  131. {
  132.     update_topline();
  133.     if (must_redraw)
  134.     update_screen(0);
  135. }
  136.  
  137. /*
  138.  * Update curwin->w_topline to move the cursor onto the screen.
  139.  */
  140.     void
  141. update_topline()
  142. {
  143.     long    line_count;
  144.     int        halfheight;
  145.     int        n;
  146.     linenr_T    old_topline;
  147. #ifdef FEAT_DIFF
  148.     int        old_topfill;
  149. #endif
  150. #ifdef FEAT_FOLDING
  151.     linenr_T    lnum;
  152. #endif
  153.     int        check_topline = FALSE;
  154.     int        check_botline = FALSE;
  155. #ifdef FEAT_MOUSE
  156.     int        save_so = p_so;
  157. #endif
  158.  
  159.     if (!screen_valid(TRUE))
  160.     return;
  161.  
  162.     check_cursor_moved(curwin);
  163.     if (curwin->w_valid & VALID_TOPLINE)
  164.     return;
  165.  
  166. #ifdef FEAT_MOUSE
  167.     /* When dragging with the mouse, don't scroll that quickly */
  168.     if (mouse_dragging)
  169.     p_so = mouse_dragging - 1;
  170. #endif
  171.  
  172.     old_topline = curwin->w_topline;
  173. #ifdef FEAT_DIFF
  174.     old_topfill = curwin->w_topfill;
  175. #endif
  176.  
  177.     /*
  178.      * If the buffer is empty, always set topline to 1.
  179.      */
  180.     if (bufempty())        /* special case - file is empty */
  181.     {
  182.     if (curwin->w_topline != 1)
  183.         redraw_later(NOT_VALID);
  184.     curwin->w_topline = 1;
  185. #ifdef FEAT_DIFF
  186.     curwin->w_topfill = 0;
  187. #endif
  188.     curwin->w_botline = 2;
  189.     curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  190. #ifdef FEAT_SCROLLBIND
  191.     curwin->w_scbind_pos = 1;
  192. #endif
  193.     }
  194.  
  195.     /*
  196.      * If the cursor is above or near the top of the window, scroll the window
  197.      * to show the line the cursor is in, with 'scrolloff' context.
  198.      */
  199.     else
  200.     {
  201.     if (curwin->w_topline > 1)
  202.     {
  203.         /* If the cursor is above topline, scrolling is always needed.
  204.          * If the cursor is far below topline and there is no folding,
  205.          * scrolling down is never needed. */
  206.         if (curwin->w_cursor.lnum < curwin->w_topline)
  207.         check_topline = TRUE;
  208.         else if (check_top_offset())
  209.         check_topline = TRUE;
  210. #ifdef FEAT_DIFF
  211.         /* Check if there are more filler lines than allowed. */
  212.         else if (curwin->w_topfill > diff_check_fill(curwin,
  213.                                curwin->w_topline))
  214.         check_topline = TRUE;
  215. #endif
  216.     }
  217.  
  218.     if (check_topline)
  219.     {
  220.         halfheight = curwin->w_height / 2 - 1;
  221.         if (halfheight < 2)
  222.         halfheight = 2;
  223.  
  224. #ifdef FEAT_FOLDING
  225.         if (hasAnyFolding(curwin))
  226.         {
  227.         /* Count the number of logical lines between the cursor and
  228.          * topline + p_so (approximation of how much will be
  229.          * scrolled). */
  230.         n = 0;
  231.         for (lnum = curwin->w_cursor.lnum;
  232.                       lnum < curwin->w_topline + p_so; ++lnum)
  233.         {
  234.             ++n;
  235.             /* stop at end of file or when we know we are far off */
  236.             if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight)
  237.             break;
  238.             (void)hasFolding(lnum, NULL, &lnum);
  239.         }
  240.         }
  241.         else
  242. #endif
  243.         n = curwin->w_topline + p_so - curwin->w_cursor.lnum;
  244.  
  245.         /* If we weren't very close to begin with, we scroll to put the
  246.          * cursor in the middle of the window.  Otherwise put the cursor
  247.          * near the top of the window. */
  248.         if (n >= halfheight)
  249.         scroll_cursor_halfway(FALSE);
  250.         else
  251.         {
  252.         scroll_cursor_top((int)p_sj, FALSE);
  253.         check_botline = TRUE;
  254.         }
  255.     }
  256.  
  257.     else
  258.     {
  259. #ifdef FEAT_FOLDING
  260.         /* Make sure topline is the first line of a fold. */
  261.         (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  262. #endif
  263.         check_botline = TRUE;
  264.     }
  265.     }
  266.  
  267.     /*
  268.      * If the cursor is below the bottom of the window, scroll the window
  269.      * to put the cursor on the window.
  270.      * When w_botline is invalid, recompute it first, to avoid a redraw later.
  271.      * If w_botline was approximated, we might need a redraw later in a few
  272.      * cases, but we don't want to spend (a lot of) time recomputing w_botline
  273.      * for every small change.
  274.      */
  275.     if (check_botline)
  276.     {
  277.     if (!(curwin->w_valid & VALID_BOTLINE_AP))
  278.         validate_botline();
  279.  
  280.     if (curwin->w_botline <= curbuf->b_ml.ml_line_count)
  281.     {
  282.         if (curwin->w_cursor.lnum < curwin->w_botline
  283.             && ((long)curwin->w_cursor.lnum
  284.                          >= (long)curwin->w_botline - p_so
  285. #ifdef FEAT_FOLDING
  286.             || hasAnyFolding(curwin)
  287. #endif
  288.             ))
  289.         {
  290.         lineoff_T    loff;
  291.  
  292.         /* Cursor is above botline, check if there are 'scrolloff'
  293.          * window lines below the cursor.  If not, need to scroll. */
  294.         n = curwin->w_empty_rows;
  295.         loff.lnum = curwin->w_cursor.lnum;
  296. #ifdef FEAT_DIFF
  297.         loff.fill = 0;
  298.         n += curwin->w_filler_rows;
  299. #endif
  300.         loff.height = 0;
  301.         while (loff.lnum < curwin->w_botline
  302. #ifdef FEAT_DIFF
  303.             && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0)
  304. #endif
  305.             )
  306.         {
  307.             n += loff.height;
  308.             if (n >= p_so)
  309.             break;
  310.             botline_forw(&loff);
  311.         }
  312.         if (n >= p_so)
  313.             /* sufficient context, no need to scroll */
  314.             check_botline = FALSE;
  315.         }
  316.         if (check_botline)
  317.         {
  318. #ifdef FEAT_FOLDING
  319.         if (hasAnyFolding(curwin))
  320.         {
  321.             /* Count the number of logical lines between the cursor and
  322.              * botline - p_so (approximation of how much will be
  323.              * scrolled). */
  324.             line_count = 0;
  325.             for (lnum = curwin->w_cursor.lnum;
  326.                      lnum >= curwin->w_botline - p_so; --lnum)
  327.             {
  328.             ++line_count;
  329.             /* stop at end of file or when we know we are far off */
  330.             if (lnum <= 0 || line_count > curwin->w_height + 1)
  331.                 break;
  332.             (void)hasFolding(lnum, &lnum, NULL);
  333.             }
  334.         }
  335.         else
  336. #endif
  337.             line_count = curwin->w_cursor.lnum - curwin->w_botline
  338.                                    + 1 + p_so;
  339.         if (line_count <= curwin->w_height + 1)
  340.             scroll_cursor_bot((int)p_sj, FALSE);
  341.         else
  342.             scroll_cursor_halfway(FALSE);
  343.         }
  344.     }
  345.     }
  346.     curwin->w_valid |= VALID_TOPLINE;
  347.  
  348.     /*
  349.      * Need to redraw when topline changed.
  350.      */
  351.     if (curwin->w_topline != old_topline
  352. #ifdef FEAT_DIFF
  353.         || curwin->w_topfill != old_topfill
  354. #endif
  355.         )
  356.     {
  357.     dollar_vcol = 0;
  358.     if (curwin->w_skipcol)
  359.     {
  360.         curwin->w_skipcol = 0;
  361.         redraw_later(NOT_VALID);
  362.     }
  363.     else
  364.         redraw_later(VALID);
  365.     /* May need to set w_skipcol when cursor in w_topline. */
  366.     if (curwin->w_cursor.lnum == curwin->w_topline)
  367.         validate_cursor();
  368.     }
  369.  
  370. #ifdef FEAT_MOUSE
  371.     p_so = save_so;
  372. #endif
  373. }
  374.  
  375. /*
  376.  * Return TRUE when there are not 'scrolloff' lines above the cursor for the
  377.  * current window.
  378.  */
  379.     static int
  380. check_top_offset()
  381. {
  382.     lineoff_T    loff;
  383.     int        n;
  384.  
  385.     if (curwin->w_cursor.lnum < curwin->w_topline + p_so
  386. #ifdef FEAT_FOLDING
  387.             || hasAnyFolding(curwin)
  388. #endif
  389.         )
  390.     {
  391.     loff.lnum = curwin->w_cursor.lnum;
  392. #ifdef FEAT_DIFF
  393.     loff.fill = 0;
  394.     n = curwin->w_topfill;        /* always have this context */
  395. #else
  396.     n = 0;
  397. #endif
  398.     /* Count the visible screen lines above the cursor line. */
  399.     while (n < p_so)
  400.     {
  401.         topline_back(&loff);
  402.         /* Stop when included a line above the window. */
  403.         if (loff.lnum < curwin->w_topline
  404. #ifdef FEAT_DIFF
  405.             || (loff.lnum == curwin->w_topline && loff.fill > 0)
  406. #endif
  407.             )
  408.         break;
  409.         n += loff.height;
  410.     }
  411.     if (n < p_so)
  412.         return TRUE;
  413.     }
  414.     return FALSE;
  415. }
  416.  
  417.     void
  418. update_curswant()
  419. {
  420.     if (curwin->w_set_curswant)
  421.     {
  422.     validate_virtcol();
  423.     curwin->w_curswant = curwin->w_virtcol;
  424.     curwin->w_set_curswant = FALSE;
  425.     }
  426. }
  427.  
  428. /*
  429.  * Check if the cursor has moved.  Set the w_valid flag accordingly.
  430.  */
  431.     void
  432. check_cursor_moved(wp)
  433.     win_T    *wp;
  434. {
  435.     if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum)
  436.     {
  437.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
  438.                      |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE);
  439.     wp->w_valid_cursor = wp->w_cursor;
  440.     wp->w_valid_leftcol = wp->w_leftcol;
  441.     }
  442.     else if (wp->w_cursor.col != wp->w_valid_cursor.col
  443.          || wp->w_leftcol != wp->w_valid_leftcol
  444. #ifdef FEAT_VIRTUALEDIT
  445.          || wp->w_cursor.coladd != wp->w_valid_cursor.coladd
  446. #endif
  447.          )
  448.     {
  449.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
  450.     wp->w_valid_cursor.col = wp->w_cursor.col;
  451.     wp->w_valid_leftcol = wp->w_leftcol;
  452. #ifdef FEAT_VIRTUALEDIT
  453.     wp->w_valid_cursor.coladd = wp->w_cursor.coladd;
  454. #endif
  455.     }
  456. }
  457.  
  458. /*
  459.  * Call this function when some window settings have changed, which require
  460.  * the cursor position, botline and topline to be recomputed and the window to
  461.  * be redrawn.  E.g, when changing the 'wrap' option or folding.
  462.  */
  463.     void
  464. changed_window_setting()
  465. {
  466.     curwin->w_lines_valid = 0;
  467.     changed_line_abv_curs();
  468.     curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE);
  469.     redraw_later(NOT_VALID);
  470. }
  471.  
  472. /*
  473.  * Set wp->w_topline to a certain number.
  474.  */
  475.     void
  476. set_topline(wp, lnum)
  477.     win_T    *wp;
  478.     linenr_T    lnum;
  479. {
  480. #ifdef FEAT_FOLDING
  481.     /* go to first of folded lines */
  482.     (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
  483. #endif
  484.     /* Approximate the value of w_botline */
  485.     wp->w_botline += lnum - wp->w_topline;
  486.     wp->w_topline = lnum;
  487. #ifdef FEAT_DIFF
  488.     wp->w_topfill = 0;
  489. #endif
  490.     wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE);
  491.     /* Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked. */
  492.     redraw_later(VALID);
  493. }
  494.  
  495. /*
  496.  * Call this function when the length of the cursor line (in screen
  497.  * characters) has changed, and the change is before the cursor.
  498.  * Need to take care of w_botline separately!
  499.  */
  500.     void
  501. changed_cline_bef_curs()
  502. {
  503.     curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
  504.                         |VALID_CHEIGHT|VALID_TOPLINE);
  505. }
  506.  
  507.     void
  508. changed_cline_bef_curs_win(wp)
  509.     win_T    *wp;
  510. {
  511.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
  512.                         |VALID_CHEIGHT|VALID_TOPLINE);
  513. }
  514.  
  515. #if 0 /* not used */
  516. /*
  517.  * Call this function when the length of the cursor line (in screen
  518.  * characters) has changed, and the position of the cursor doesn't change.
  519.  * Need to take care of w_botline separately!
  520.  */
  521.     void
  522. changed_cline_aft_curs()
  523. {
  524.     curwin->w_valid &= ~VALID_CHEIGHT;
  525. }
  526. #endif
  527.  
  528. /*
  529.  * Call this function when the length of a line (in screen characters) above
  530.  * the cursor have changed.
  531.  * Need to take care of w_botline separately!
  532.  */
  533.     void
  534. changed_line_abv_curs()
  535. {
  536.     curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
  537.                         |VALID_CHEIGHT|VALID_TOPLINE);
  538. }
  539.  
  540.     void
  541. changed_line_abv_curs_win(wp)
  542.     win_T    *wp;
  543. {
  544.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
  545.                         |VALID_CHEIGHT|VALID_TOPLINE);
  546. }
  547.  
  548. /*
  549.  * Make sure the value of curwin->w_botline is valid.
  550.  */
  551.     void
  552. validate_botline()
  553. {
  554.     if (!(curwin->w_valid & VALID_BOTLINE))
  555.     comp_botline(curwin);
  556. }
  557.  
  558. /*
  559.  * Make sure the value of wp->w_botline is valid.
  560.  */
  561.     static void
  562. validate_botline_win(wp)
  563.     win_T    *wp;
  564. {
  565.     if (!(wp->w_valid & VALID_BOTLINE))
  566.     comp_botline(wp);
  567. }
  568.  
  569. /*
  570.  * Mark curwin->w_botline as invalid (because of some change in the buffer).
  571.  */
  572.     void
  573. invalidate_botline()
  574. {
  575.     curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  576. }
  577.  
  578.     void
  579. invalidate_botline_win(wp)
  580.     win_T    *wp;
  581. {
  582.     wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  583. }
  584.  
  585. #if 0 /* never used */
  586. /*
  587.  * Mark curwin->w_botline as approximated (because of some small change in the
  588.  * buffer).
  589.  */
  590.     void
  591. approximate_botline()
  592. {
  593.     curwin->w_valid &= ~VALID_BOTLINE;
  594. }
  595. #endif
  596.  
  597.     void
  598. approximate_botline_win(wp)
  599.     win_T    *wp;
  600. {
  601.     wp->w_valid &= ~VALID_BOTLINE;
  602. }
  603.  
  604. #if 0 /* not used */
  605. /*
  606.  * Return TRUE if curwin->w_botline is valid.
  607.  */
  608.     int
  609. botline_valid()
  610. {
  611.     return (curwin->w_valid & VALID_BOTLINE);
  612. }
  613. #endif
  614.  
  615. #if 0 /* not used */
  616. /*
  617.  * Return TRUE if curwin->w_botline is valid or approximated.
  618.  */
  619.     int
  620. botline_approximated()
  621. {
  622.     return (curwin->w_valid & VALID_BOTLINE_AP);
  623. }
  624. #endif
  625.  
  626. /*
  627.  * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid.
  628.  */
  629.     int
  630. cursor_valid()
  631. {
  632.     check_cursor_moved(curwin);
  633.     return ((curwin->w_valid & (VALID_WROW|VALID_WCOL)) ==
  634.                               (VALID_WROW|VALID_WCOL));
  635. }
  636.  
  637. /*
  638.  * Validate cursor position.  Makes sure w_wrow and w_wcol are valid.
  639.  * w_topline must be valid, you may need to call update_topline() first!
  640.  */
  641.     void
  642. validate_cursor()
  643. {
  644.     check_cursor_moved(curwin);
  645.     if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
  646.     curs_columns(TRUE);
  647. }
  648.  
  649. #if defined(FEAT_GUI) || defined(PROTO)
  650. /*
  651.  * validate w_cline_row.
  652.  */
  653.     void
  654. validate_cline_row()
  655. {
  656.     /*
  657.      * First make sure that w_topline is valid (after moving the cursor).
  658.      */
  659.     update_topline();
  660.     check_cursor_moved(curwin);
  661.     if (!(curwin->w_valid & VALID_CROW))
  662.     curs_rows(curwin, FALSE);
  663. }
  664. #endif
  665.  
  666. /*
  667.  * Compute wp->w_cline_row and wp->w_cline_height, based on the current value
  668.  * of wp->w_topine.
  669.  *
  670.  * Returns OK when cursor is in the window, FAIL when it isn't.
  671.  */
  672.     static void
  673. curs_rows(wp, do_botline)
  674.     win_T    *wp;
  675.     int        do_botline;        /* also compute w_botline */
  676. {
  677.     linenr_T    lnum;
  678.     int        i;
  679.     int        all_invalid;
  680.     int        valid;
  681. #ifdef FEAT_FOLDING
  682.     long    fold_count;
  683. #endif
  684.  
  685.     /* Check if wp->w_lines[].wl_size is invalid */
  686.     all_invalid = (!redrawing()
  687.             || wp->w_lines_valid == 0
  688.             || wp->w_lines[0].wl_lnum > wp->w_topline);
  689.     i = 0;
  690.     wp->w_cline_row = 0;
  691.     for (lnum = wp->w_topline; lnum < wp->w_cursor.lnum; ++i)
  692.     {
  693.     valid = FALSE;
  694.     if (!all_invalid && i < wp->w_lines_valid)
  695.     {
  696.         if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid)
  697.         continue;        /* skip changed or deleted lines */
  698.         if (wp->w_lines[i].wl_lnum == lnum)
  699.         {
  700. #ifdef FEAT_FOLDING
  701.         /* Check for newly inserted lines below this row, in which
  702.          * case we need to check for folded lines. */
  703.         if (!wp->w_buffer->b_mod_set
  704.             || wp->w_lines[i].wl_lastlnum < wp->w_cursor.lnum
  705.             || wp->w_buffer->b_mod_top
  706.                          > wp->w_lines[i].wl_lastlnum + 1)
  707. #endif
  708.         valid = TRUE;
  709.         }
  710.         else if (wp->w_lines[i].wl_lnum > lnum)
  711.         --i;            /* hold at inserted lines */
  712.     }
  713.     if (valid
  714. #ifdef FEAT_DIFF
  715.         && (lnum != wp->w_topline || !wp->w_p_diff)
  716. #endif
  717.         )
  718.     {
  719. #ifdef FEAT_FOLDING
  720.         lnum = wp->w_lines[i].wl_lastlnum + 1;
  721.         /* Cursor inside folded lines, don't count this row */
  722.         if (lnum > wp->w_cursor.lnum)
  723.         break;
  724. #else
  725.         ++lnum;
  726. #endif
  727.         wp->w_cline_row += wp->w_lines[i].wl_size;
  728.     }
  729.     else
  730.     {
  731. #ifdef FEAT_FOLDING
  732.         fold_count = foldedCount(wp, lnum, NULL);
  733.         if (fold_count)
  734.         {
  735.         lnum += fold_count;
  736.         if (lnum > wp->w_cursor.lnum)
  737.             break;
  738.         ++wp->w_cline_row;
  739.         }
  740.         else
  741. #endif
  742. #ifdef FEAT_DIFF
  743.         if (lnum == wp->w_topline)
  744.             wp->w_cline_row += plines_win_nofill(wp, lnum++, TRUE)
  745.             + wp->w_topfill;
  746.         else
  747. #endif
  748.             wp->w_cline_row += plines_win(wp, lnum++, TRUE);
  749.     }
  750.     }
  751.  
  752.     check_cursor_moved(wp);
  753.     if (!(wp->w_valid & VALID_CHEIGHT))
  754.     {
  755.     if (all_invalid
  756.         || i == wp->w_lines_valid
  757.         || (i < wp->w_lines_valid
  758.             && (!wp->w_lines[i].wl_valid
  759.             || wp->w_lines[i].wl_lnum != wp->w_cursor.lnum)))
  760.     {
  761. #ifdef FEAT_DIFF
  762.         if (wp->w_cursor.lnum == wp->w_topline)
  763.         wp->w_cline_height = plines_win_nofill(wp, wp->w_cursor.lnum,
  764.                             TRUE) + wp->w_topfill;
  765.         else
  766. #endif
  767.         wp->w_cline_height = plines_win(wp, wp->w_cursor.lnum, TRUE);
  768. #ifdef FEAT_FOLDING
  769.         wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
  770.                               NULL, NULL, TRUE, NULL);
  771. #endif
  772.     }
  773.     else if (i > wp->w_lines_valid)
  774.     {
  775.         /* a line that is too long to fit on the last screen line */
  776.         wp->w_cline_height = 0;
  777. #ifdef FEAT_FOLDING
  778.         wp->w_cline_folded = FALSE;
  779. #endif
  780.     }
  781.     else
  782.     {
  783.         wp->w_cline_height = wp->w_lines[i].wl_size;
  784. #ifdef FEAT_FOLDING
  785.         wp->w_cline_folded = wp->w_lines[i].wl_folded;
  786. #endif
  787.     }
  788.     }
  789.  
  790.     wp->w_valid |= VALID_CROW|VALID_CHEIGHT;
  791.  
  792.     /* validate botline too, if update_screen doesn't do it */
  793.     if (do_botline && all_invalid)
  794.     validate_botline_win(wp);
  795. }
  796.  
  797. /*
  798.  * Validate curwin->w_virtcol only.
  799.  */
  800.     void
  801. validate_virtcol()
  802. {
  803.     validate_virtcol_win(curwin);
  804. }
  805.  
  806. /*
  807.  * Validate wp->w_virtcol only.
  808.  */
  809.     void
  810. validate_virtcol_win(wp)
  811.     win_T    *wp;
  812. {
  813.     check_cursor_moved(wp);
  814.     if (!(wp->w_valid & VALID_VIRTCOL))
  815.     {
  816.     getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
  817.     wp->w_valid |= VALID_VIRTCOL;
  818.     }
  819. }
  820.  
  821. /*
  822.  * Validate curwin->w_cline_height only.
  823.  */
  824.     static void
  825. validate_cheight()
  826. {
  827.     check_cursor_moved(curwin);
  828.     if (!(curwin->w_valid & VALID_CHEIGHT))
  829.     {
  830. #ifdef FEAT_DIFF
  831.     if (curwin->w_cursor.lnum == curwin->w_topline)
  832.         curwin->w_cline_height = plines_nofill(curwin->w_cursor.lnum)
  833.                               + curwin->w_topfill;
  834.     else
  835. #endif
  836.         curwin->w_cline_height = plines(curwin->w_cursor.lnum);
  837. #ifdef FEAT_FOLDING
  838.     curwin->w_cline_folded = hasFolding(curwin->w_cursor.lnum, NULL, NULL);
  839. #endif
  840.     curwin->w_valid |= VALID_CHEIGHT;
  841.     }
  842. }
  843.  
  844. /*
  845.  * validate w_wcol and w_virtcol only.    Only correct when 'wrap' on!
  846.  */
  847.     void
  848. validate_cursor_col()
  849. {
  850.     colnr_T off;
  851.     colnr_T col;
  852.  
  853.     validate_virtcol();
  854.     if (!(curwin->w_valid & VALID_WCOL))
  855.     {
  856.     col = curwin->w_virtcol;
  857.     off = curwin_col_off();
  858.     col += off;
  859.  
  860.     /* long line wrapping, adjust curwin->w_wrow */
  861.     if (curwin->w_p_wrap && col >= (colnr_T)W_WIDTH(curwin)
  862. #ifdef FEAT_VERTSPLIT
  863.         && curwin->w_width != 0
  864. #endif
  865.         )
  866.     {
  867.         col -= W_WIDTH(curwin);
  868.         col = col % (W_WIDTH(curwin) - off + curwin_col_off2());
  869.     }
  870.     curwin->w_wcol = col;
  871.     curwin->w_valid |= VALID_WCOL;
  872.     }
  873. }
  874.  
  875. /*
  876.  * Compute offset of a window, occupied by line number, fold column and sign
  877.  * column (these don't move when scrolling horizontally).
  878.  */
  879.     int
  880. win_col_off(wp)
  881.     win_T    *wp;
  882. {
  883.     return ((wp->w_p_nu ? 8 : 0)
  884. #ifdef FEAT_CMDWIN
  885.         + (cmdwin_type == 0 || wp != curwin ? 0 : 1)
  886. #endif
  887. #ifdef FEAT_FOLDING
  888.         + wp->w_p_fdc
  889. #endif
  890. #ifdef FEAT_SIGNS
  891.         + (wp->w_buffer->b_signlist != NULL ? 2 : 0)
  892. #endif
  893.        );
  894. }
  895.  
  896.     int
  897. curwin_col_off()
  898. {
  899.     return win_col_off(curwin);
  900. }
  901.  
  902. /*
  903.  * Return the difference in column offset for the second screen line of a
  904.  * wrapped line.  It's 8 if 'number' is on and 'n' is in 'cpoptions'.
  905.  */
  906.     int
  907. win_col_off2(wp)
  908.     win_T    *wp;
  909. {
  910.     if (wp->w_p_nu && vim_strchr(p_cpo, CPO_NUMCOL) != NULL)
  911.     return 8;
  912.     return 0;
  913. }
  914.  
  915.     int
  916. curwin_col_off2()
  917. {
  918.     return win_col_off2(curwin);
  919. }
  920.  
  921. /*
  922.  * compute curwin->w_wcol and curwin->w_virtcol.
  923.  * Also updates curwin->w_wrow and curwin->w_cline_row.
  924.  * Also updates curwin->w_leftcol.
  925.  */
  926.     void
  927. curs_columns(scroll)
  928.     int        scroll;        /* when TRUE, may scroll horizontally */
  929. {
  930.     int        diff;
  931.     int        extra;        /* offset for first screen line */
  932.     int        off;
  933.     int        n;
  934.     int        width = 0;
  935.     int        textwidth;
  936.     int        new_leftcol;
  937.     colnr_T    startcol;
  938.     colnr_T    endcol;
  939.     colnr_T    prev_skipcol;
  940.  
  941.     /*
  942.      * First make sure that w_topline is valid (after moving the cursor).
  943.      */
  944.     update_topline();
  945.  
  946.     /*
  947.      * Next make sure that w_cline_row is valid.
  948.      */
  949.     if (!(curwin->w_valid & VALID_CROW))
  950.     curs_rows(curwin, FALSE);
  951.  
  952.     /*
  953.      * Compute the number of virtual columns.
  954.      */
  955. #ifdef FEAT_FOLDING
  956.     if (curwin->w_cline_folded)
  957.     /* In a folded line the cursor is always in the first column */
  958.     startcol = curwin->w_virtcol = endcol = curwin->w_leftcol;
  959.     else
  960. #endif
  961.     getvvcol(curwin, &curwin->w_cursor,
  962.                 &startcol, &(curwin->w_virtcol), &endcol);
  963.  
  964.     /* remove '$' from change command when cursor moves onto it */
  965.     if (startcol > dollar_vcol)
  966.     dollar_vcol = 0;
  967.  
  968.     extra = curwin_col_off();
  969.     curwin->w_wcol = curwin->w_virtcol + extra;
  970.     endcol += extra;
  971.  
  972.     /*
  973.      * Now compute w_wrow, counting screen lines from w_cline_row.
  974.      */
  975.     curwin->w_wrow = curwin->w_cline_row;
  976.  
  977.     textwidth = W_WIDTH(curwin) - extra;
  978.     if (textwidth <= 0)
  979.     {
  980.     /* No room for text, put cursor in last char of window. */
  981.     curwin->w_wcol = W_WIDTH(curwin) - 1;
  982.     curwin->w_wrow = curwin->w_height - 1;
  983.     }
  984.     else if (curwin->w_p_wrap
  985. #ifdef FEAT_VERTSPLIT
  986.         && curwin->w_width != 0
  987. #endif
  988.         )
  989.     {
  990.     width = textwidth + curwin_col_off2();
  991.  
  992.     /* long line wrapping, adjust curwin->w_wrow */
  993.     if (curwin->w_wcol >= W_WIDTH(curwin))
  994.     {
  995.         n = (curwin->w_wcol - W_WIDTH(curwin)) / width + 1;
  996.         curwin->w_wcol -= n * width;
  997.         curwin->w_wrow += n;
  998.  
  999. #ifdef FEAT_LINEBREAK
  1000.         /* When cursor wraps to first char of next line in Insert
  1001.          * mode, the 'showbreak' string isn't shown, backup to first
  1002.          * column */
  1003.         if (*p_sbr && *ml_get_cursor() == NUL
  1004.             && curwin->w_wcol == (int)STRLEN(p_sbr))
  1005.         curwin->w_wcol = 0;
  1006. #endif
  1007.     }
  1008.     }
  1009.  
  1010.     /* No line wrapping: compute curwin->w_leftcol if scrolling is on and line
  1011.      * is not folded.
  1012.      * If scrolling is off, curwin->w_leftcol is assumed to be 0 */
  1013.     else if (scroll
  1014. #ifdef FEAT_FOLDING
  1015.         && !curwin->w_cline_folded
  1016. #endif
  1017.         )
  1018.     {
  1019.     /*
  1020.      * If Cursor is left of the screen, scroll rightwards.
  1021.      * If Cursor is right of the screen, scroll leftwards
  1022.      * If we get closer to the edge than 'sidescrolloff', scroll a little
  1023.      * extra
  1024.      */
  1025.     if ((off = (int)startcol - (int)curwin->w_leftcol - p_siso) < 0
  1026.         || (off = (int)endcol
  1027.              - (int)(curwin->w_leftcol + W_WIDTH(curwin) - p_siso)
  1028.              + 1) > 0)
  1029.     {
  1030.         if (off < 0)
  1031.         diff = -off;
  1032.         else
  1033.         diff = off;
  1034.  
  1035.         /* far off, put cursor in middle of window */
  1036.         if (p_ss == 0 || diff >= textwidth / 2)
  1037.         new_leftcol = curwin->w_wcol - extra - textwidth / 2;
  1038.         else
  1039.         {
  1040.         if (diff < p_ss)
  1041.             diff = p_ss;
  1042.         if (off < 0)
  1043.             new_leftcol = curwin->w_leftcol - diff;
  1044.         else
  1045.             new_leftcol = curwin->w_leftcol + diff;
  1046.         }
  1047.         if (new_leftcol < 0)
  1048.         new_leftcol = 0;
  1049.         if (new_leftcol != (int)curwin->w_leftcol)
  1050.         {
  1051.         curwin->w_leftcol = new_leftcol;
  1052.         /* screen has to be redrawn with new curwin->w_leftcol */
  1053.         redraw_later(NOT_VALID);
  1054.         }
  1055.     }
  1056.     curwin->w_wcol -= curwin->w_leftcol;
  1057.     }
  1058.     else if (curwin->w_wcol > (int)curwin->w_leftcol)
  1059.     curwin->w_wcol -= curwin->w_leftcol;
  1060.     else
  1061.     curwin->w_wcol = 0;
  1062.  
  1063. #ifdef FEAT_DIFF
  1064.     /* Skip over filler lines.  At the top use w_topfill, there
  1065.      * may be some filler lines above the window. */
  1066.     if (curwin->w_cursor.lnum == curwin->w_topline)
  1067.     curwin->w_wrow += curwin->w_topfill;
  1068.     else
  1069.     curwin->w_wrow += diff_check_fill(curwin, curwin->w_cursor.lnum);
  1070. #endif
  1071.  
  1072.     prev_skipcol = curwin->w_skipcol;
  1073.  
  1074.     n = 0;
  1075.     if ((curwin->w_wrow >= curwin->w_height
  1076.         || ((prev_skipcol > 0
  1077.             || curwin->w_wrow + p_so >= curwin->w_height)
  1078.             && (n =
  1079. #ifdef FEAT_DIFF
  1080.             plines_win_nofill
  1081. #else
  1082.             plines_win
  1083. #endif
  1084.             (curwin, curwin->w_cursor.lnum, FALSE))
  1085.                             - 1 >= curwin->w_height))
  1086.         && curwin->w_height != 0
  1087.         && curwin->w_cursor.lnum == curwin->w_topline
  1088. #ifdef FEAT_VERTSPLIT
  1089.         && curwin->w_width != 0
  1090. #endif
  1091.         )
  1092.     {
  1093.     /* Cursor past end of screen.  Happens with a single line that does
  1094.      * not fit on screen.  Find a skipcol to show the text around the
  1095.      * cursor.  Avoid scrolling all the time. compute value of "extra":
  1096.      * 1: Less than "p_so" lines above
  1097.      * 2: Less than "p_so" lines below
  1098.      * 3: both of them */
  1099.     extra = 0;
  1100.     if (curwin->w_skipcol + p_so * width > curwin->w_virtcol)
  1101.         extra = 1;
  1102.     /* Compute last display line of the buffer line that we want at the
  1103.      * bottom of the window. */
  1104.     if (n == 0)
  1105.         n = plines_win(curwin, curwin->w_cursor.lnum, FALSE);
  1106.     --n;
  1107.     if (curwin->w_wrow + p_so < n)
  1108.         n = curwin->w_wrow + p_so;
  1109.     if ((colnr_T)n >= curwin->w_height + curwin->w_skipcol / width)
  1110.         extra += 2;
  1111.  
  1112.     if (extra == 3)
  1113.     {
  1114.         /* not enough room for 'scrolloff', put cursor in the middle */
  1115.         n = curwin->w_virtcol / width;
  1116.         if (n > curwin->w_height / 2)
  1117.         n -= curwin->w_height / 2;
  1118.         else
  1119.         n = 0;
  1120.         curwin->w_skipcol = n * width;
  1121.     }
  1122.     else if (extra == 1)
  1123.     {
  1124.         /* less then 'scrolloff' lines above, decrease skipcol */
  1125.         extra = (curwin->w_skipcol + p_so * width - curwin->w_virtcol
  1126.                      + width - 1) / width;
  1127.         if (extra > 0)
  1128.         {
  1129.         if ((colnr_T)(extra * width) > curwin->w_skipcol)
  1130.             extra = curwin->w_skipcol / width;
  1131.         curwin->w_skipcol -= extra * width;
  1132.         }
  1133.     }
  1134.     else if (extra == 2)
  1135.     {
  1136.         /* less then 'scrolloff' lines below, increase skipcol */
  1137.         endcol = (n - curwin->w_height + 1) * width;
  1138.         if (endcol > curwin->w_skipcol)
  1139.         curwin->w_skipcol = endcol;
  1140.     }
  1141.  
  1142.     curwin->w_wrow -= curwin->w_skipcol / width;
  1143.     if (curwin->w_wrow >= curwin->w_height)
  1144.     {
  1145.         /* small window, make sure cursor is in it */
  1146.         extra = curwin->w_wrow - curwin->w_height + 1;
  1147.         curwin->w_skipcol += extra * width;
  1148.         curwin->w_wrow -= extra;
  1149.     }
  1150.  
  1151.     extra = (curwin->w_skipcol - prev_skipcol) / width;
  1152.     if (extra > 0)
  1153.         win_ins_lines(curwin, 0, extra, FALSE, FALSE);
  1154.     else if (extra < 0)
  1155.         win_del_lines(curwin, 0, -extra, FALSE, FALSE);
  1156.  
  1157.     }
  1158.     else
  1159.     curwin->w_skipcol = 0;
  1160.     if (prev_skipcol != curwin->w_skipcol)
  1161.     redraw_later(NOT_VALID);
  1162.  
  1163.     curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
  1164. }
  1165.  
  1166. /*
  1167.  * Scroll the current window down by "line_count" logical lines.  "CTRL-Y"
  1168.  */
  1169. /*ARGSUSED*/
  1170.     void
  1171. scrolldown(line_count, byfold)
  1172.     long    line_count;
  1173.     int        byfold;        /* TRUE: count a closed fold as one line */
  1174. {
  1175.     long    done = 0;    /* total # of physical lines done */
  1176.     int        wrow;
  1177.     int        moved = FALSE;
  1178.  
  1179. #ifdef FEAT_FOLDING
  1180.     linenr_T    first;
  1181.  
  1182.     /* Make sure w_topline is at the first of a sequence of folded lines. */
  1183.     (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  1184. #endif
  1185.     validate_cursor();        /* w_wrow needs to be valid */
  1186.     while (line_count-- > 0)
  1187.     {
  1188. #ifdef FEAT_DIFF
  1189.     if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
  1190.     {
  1191.         ++curwin->w_topfill;
  1192.         ++done;
  1193.     }
  1194.     else
  1195. #endif
  1196.     {
  1197.         if (curwin->w_topline == 1)
  1198.         break;
  1199.         --curwin->w_topline;
  1200. #ifdef FEAT_DIFF
  1201.         curwin->w_topfill = 0;
  1202. #endif
  1203. #ifdef FEAT_FOLDING
  1204.         /* A sequence of folded lines only counts for one logical line */
  1205.         if (hasFolding(curwin->w_topline, &first, NULL))
  1206.         {
  1207.         ++done;
  1208.         if (!byfold)
  1209.             line_count -= curwin->w_topline - first - 1;
  1210.         curwin->w_botline -= curwin->w_topline - first;
  1211.         curwin->w_topline = first;
  1212.         }
  1213.         else
  1214. #endif
  1215. #ifdef FEAT_DIFF
  1216.         done += plines_nofill(curwin->w_topline);
  1217. #else
  1218.         done += plines(curwin->w_topline);
  1219. #endif
  1220.     }
  1221.     --curwin->w_botline;        /* approximate w_botline */
  1222.     invalidate_botline();
  1223.     }
  1224.     curwin->w_wrow += done;        /* keep w_wrow updated */
  1225.     curwin->w_cline_row += done;    /* keep w_cline_row updated */
  1226.  
  1227. #ifdef FEAT_DIFF
  1228.     if (curwin->w_cursor.lnum == curwin->w_topline)
  1229.     curwin->w_cline_row = 0;
  1230.     check_topfill(curwin, TRUE);
  1231. #endif
  1232.  
  1233.     /*
  1234.      * Compute the row number of the last row of the cursor line
  1235.      * and move the cursor onto the displayed part of the window.
  1236.      */
  1237.     wrow = curwin->w_wrow;
  1238.     if (curwin->w_p_wrap
  1239. #ifdef FEAT_VERTSPLIT
  1240.         && curwin->w_width != 0
  1241. #endif
  1242.         )
  1243.     {
  1244.     validate_virtcol();
  1245.     validate_cheight();
  1246.     wrow += curwin->w_cline_height - 1 -
  1247.         curwin->w_virtcol / W_WIDTH(curwin);
  1248.     }
  1249.     while (wrow >= curwin->w_height && curwin->w_cursor.lnum > 1)
  1250.     {
  1251. #ifdef FEAT_FOLDING
  1252.     if (hasFolding(curwin->w_cursor.lnum, &first, NULL))
  1253.     {
  1254.         --wrow;
  1255.         if (first == 1)
  1256.         curwin->w_cursor.lnum = 1;
  1257.         else
  1258.         curwin->w_cursor.lnum = first - 1;
  1259.     }
  1260.     else
  1261. #endif
  1262.         wrow -= plines(curwin->w_cursor.lnum--);
  1263.     curwin->w_valid &=
  1264.           ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
  1265.     moved = TRUE;
  1266.     }
  1267.     if (moved)
  1268.     {
  1269. #ifdef FEAT_FOLDING
  1270.     /* Move cursor to first line of closed fold. */
  1271.     foldAdjustCursor();
  1272. #endif
  1273.     coladvance(curwin->w_curswant);
  1274.     }
  1275. }
  1276.  
  1277. /*
  1278.  * Scroll the current window up by "line_count" logical lines.  "CTRL-E"
  1279.  */
  1280. /*ARGSUSED*/
  1281.     void
  1282. scrollup(line_count, byfold)
  1283.     long    line_count;
  1284.     int        byfold;        /* TRUE: count a closed fold as one line */
  1285. {
  1286. #if defined(FEAT_FOLDING) || defined(FEAT_DIFF)
  1287.     linenr_T    lnum;
  1288.  
  1289.     if (
  1290. # ifdef FEAT_FOLDING
  1291.         (byfold && hasAnyFolding(curwin))
  1292. #  ifdef FEAT_DIFF
  1293.         ||
  1294. #  endif
  1295. # endif
  1296. # ifdef FEAT_DIFF
  1297.         curwin->w_p_diff
  1298. # endif
  1299.         )
  1300.     {
  1301.     /* count each sequence of folded lines as one logical line */
  1302.     lnum = curwin->w_topline;
  1303.     while (line_count--)
  1304.     {
  1305. # ifdef FEAT_DIFF
  1306.         if (curwin->w_topfill > 0)
  1307.         --curwin->w_topfill;
  1308.         else
  1309. # endif
  1310.         {
  1311. # ifdef FEAT_FOLDING
  1312.         if (byfold)
  1313.             (void)hasFolding(lnum, NULL, &lnum);
  1314. # endif
  1315.         if (lnum >= curbuf->b_ml.ml_line_count)
  1316.             break;
  1317.         ++lnum;
  1318. # ifdef FEAT_DIFF
  1319.         curwin->w_topfill = diff_check_fill(curwin, lnum);
  1320. # endif
  1321.         }
  1322.     }
  1323.     /* approximate w_botline */
  1324.     curwin->w_botline += lnum - curwin->w_topline;
  1325.     curwin->w_topline = lnum;
  1326.     }
  1327.     else
  1328. #endif
  1329.     {
  1330.     curwin->w_topline += line_count;
  1331.     curwin->w_botline += line_count;    /* approximate w_botline */
  1332.     }
  1333.  
  1334.     if (curwin->w_topline > curbuf->b_ml.ml_line_count)
  1335.     curwin->w_topline = curbuf->b_ml.ml_line_count;
  1336.     if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1)
  1337.     curwin->w_botline = curbuf->b_ml.ml_line_count + 1;
  1338.  
  1339. #ifdef FEAT_DIFF
  1340.     check_topfill(curwin, FALSE);
  1341. #endif
  1342.  
  1343. #ifdef FEAT_FOLDING
  1344.     if (hasAnyFolding(curwin))
  1345.     /* Make sure w_topline is at the first of a sequence of folded lines. */
  1346.     (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  1347. #endif
  1348.  
  1349.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1350.     if (curwin->w_cursor.lnum < curwin->w_topline)
  1351.     {
  1352.     curwin->w_cursor.lnum = curwin->w_topline;
  1353.     curwin->w_valid &=
  1354.           ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
  1355.     coladvance(curwin->w_curswant);
  1356.     }
  1357. }
  1358.  
  1359. #ifdef FEAT_DIFF
  1360. /*
  1361.  * Don't end up with too many filler lines in the window.
  1362.  */
  1363.     void
  1364. check_topfill(wp, down)
  1365.     win_T    *wp;
  1366.     int        down;    /* when TRUE scroll down when not enough space */
  1367. {
  1368.     int        n;
  1369.  
  1370.     if (wp->w_topfill > 0)
  1371.     {
  1372.     n = plines_win_nofill(wp, wp->w_topline, TRUE);
  1373.     if (wp->w_topfill + n > wp->w_height)
  1374.     {
  1375.         if (down && wp->w_topline > 1)
  1376.         {
  1377.         --wp->w_topline;
  1378.         wp->w_topfill = 0;
  1379.         }
  1380.         else
  1381.         {
  1382.         wp->w_topfill = wp->w_height - n;
  1383.         if (wp->w_topfill < 0)
  1384.             wp->w_topfill = 0;
  1385.         }
  1386.     }
  1387.     }
  1388. }
  1389.  
  1390. /*
  1391.  * Use as many filler lines as possible for w_topline.  Make sure w_topline
  1392.  * is still visible.
  1393.  */
  1394.     static void
  1395. max_topfill()
  1396. {
  1397.     int        n;
  1398.  
  1399.     n = plines_nofill(curwin->w_topline);
  1400.     if (n >= curwin->w_height)
  1401.     curwin->w_topfill = 0;
  1402.     else
  1403.     {
  1404.     curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
  1405.     if (curwin->w_topfill + n > curwin->w_height)
  1406.         curwin->w_topfill = curwin->w_height - n;
  1407.     }
  1408. }
  1409. #endif
  1410.  
  1411. #if defined(FEAT_INS_EXPAND) || defined(PROTO)
  1412. /*
  1413.  * Scroll the screen one line down, but don't do it if it would move the
  1414.  * cursor off the screen.
  1415.  */
  1416.     void
  1417. scrolldown_clamp()
  1418. {
  1419.     int        end_row;
  1420. #ifdef FEAT_DIFF
  1421.     int        can_fill = (curwin->w_topfill
  1422.                 < diff_check_fill(curwin, curwin->w_topline));
  1423. #endif
  1424.  
  1425.     if (curwin->w_topline <= 1
  1426. #ifdef FEAT_DIFF
  1427.         && !can_fill
  1428. #endif
  1429.         )
  1430.     return;
  1431.  
  1432.     validate_cursor();        /* w_wrow needs to be valid */
  1433.  
  1434.     /*
  1435.      * Compute the row number of the last row of the cursor line
  1436.      * and make sure it doesn't go off the screen. Make sure the cursor
  1437.      * doesn't go past 'scrolloff' lines from the screen end.
  1438.      */
  1439.     end_row = curwin->w_wrow;
  1440. #ifdef FEAT_DIFF
  1441.     if (can_fill)
  1442.     ++end_row;
  1443.     else
  1444.     end_row += plines_nofill(curwin->w_topline - 1);
  1445. #else
  1446.     end_row += plines(curwin->w_topline - 1);
  1447. #endif
  1448.     if (curwin->w_p_wrap
  1449. #ifdef FEAT_VERTSPLIT
  1450.         && curwin->w_width != 0
  1451. #endif
  1452.         )
  1453.     {
  1454.     validate_cheight();
  1455.     validate_virtcol();
  1456.     end_row += curwin->w_cline_height - 1 -
  1457.         curwin->w_virtcol / W_WIDTH(curwin);
  1458.     }
  1459.     if (end_row < curwin->w_height - p_so)
  1460.     {
  1461. #ifdef FEAT_DIFF
  1462.     if (can_fill)
  1463.     {
  1464.         ++curwin->w_topfill;
  1465.         check_topfill(curwin, TRUE);
  1466.     }
  1467.     else
  1468.     {
  1469.         --curwin->w_topline;
  1470.         curwin->w_topfill = 0;
  1471.     }
  1472. #else
  1473.     --curwin->w_topline;
  1474. #endif
  1475.     --curwin->w_botline;        /* approximate w_botline */
  1476.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1477.     }
  1478. }
  1479.  
  1480. /*
  1481.  * Scroll the screen one line up, but don't do it if it would move the cursor
  1482.  * off the screen.
  1483.  */
  1484.     void
  1485. scrollup_clamp()
  1486. {
  1487.     int        start_row;
  1488.  
  1489.     if (curwin->w_topline == curbuf->b_ml.ml_line_count
  1490. #ifdef FEAT_DIFF
  1491.         && curwin->w_topfill == 0
  1492. #endif
  1493.         )
  1494.     return;
  1495.  
  1496.     validate_cursor();        /* w_wrow needs to be valid */
  1497.  
  1498.     /*
  1499.      * Compute the row number of the first row of the cursor line
  1500.      * and make sure it doesn't go off the screen. Make sure the cursor
  1501.      * doesn't go before 'scrolloff' lines from the screen start.
  1502.      */
  1503. #ifdef FEAT_DIFF
  1504.     start_row = curwin->w_wrow - plines_nofill(curwin->w_topline)
  1505.                               - curwin->w_topfill;
  1506. #else
  1507.     start_row = curwin->w_wrow - plines(curwin->w_topline);
  1508. #endif
  1509.     if (curwin->w_p_wrap
  1510. #ifdef FEAT_VERTSPLIT
  1511.         && curwin->w_width != 0
  1512. #endif
  1513.         )
  1514.     {
  1515.     validate_virtcol();
  1516.     start_row -= curwin->w_virtcol / W_WIDTH(curwin);
  1517.     }
  1518.     if (start_row >= p_so)
  1519.     {
  1520. #ifdef FEAT_DIFF
  1521.     if (curwin->w_topfill > 0)
  1522.         --curwin->w_topfill;
  1523.     else
  1524. #endif
  1525.         ++curwin->w_topline;
  1526.     ++curwin->w_botline;        /* approximate w_botline */
  1527.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1528.     }
  1529. }
  1530. #endif /* FEAT_INS_EXPAND */
  1531.  
  1532. /*
  1533.  * Add one line above "lp->lnum".  This can be a filler line, a closed fold or
  1534.  * a (wrapped) text line.  Uses and sets "lp->fill".
  1535.  * Returns the height of the added line in "lp->height".
  1536.  * Lines above the first one are incredibly high.
  1537.  */
  1538.     static void
  1539. topline_back(lp)
  1540.     lineoff_T    *lp;
  1541. {
  1542. #ifdef FEAT_DIFF
  1543.     if (lp->fill < diff_check_fill(curwin, lp->lnum))
  1544.     {
  1545.     /* Add a filler line. */
  1546.     ++lp->fill;
  1547.     lp->height = 1;
  1548.     }
  1549.     else
  1550. #endif
  1551.     {
  1552.     --lp->lnum;
  1553. #ifdef FEAT_DIFF
  1554.     lp->fill = 0;
  1555. #endif
  1556.     if (lp->lnum < 1)
  1557.         lp->height = MAXCOL;
  1558.     else
  1559. #ifdef FEAT_FOLDING
  1560.         if (hasFolding(lp->lnum, &lp->lnum, NULL))
  1561.         /* Add a closed fold */
  1562.         lp->height = 1;
  1563.     else
  1564. #endif
  1565.     {
  1566. #ifdef FEAT_DIFF
  1567.         lp->height = plines_nofill(lp->lnum);
  1568. #else
  1569.         lp->height = plines(lp->lnum);
  1570. #endif
  1571.     }
  1572.     }
  1573. }
  1574.  
  1575. /*
  1576.  * Add one line below "lp->lnum".  This can be a filler line, a closed fold or
  1577.  * a (wrapped) text line.  Uses and sets "lp->fill".
  1578.  * Returns the height of the added line in "lp->height".
  1579.  * Lines below the last one are incredibly high.
  1580.  */
  1581.     static void
  1582. botline_forw(lp)
  1583.     lineoff_T    *lp;
  1584. {
  1585. #ifdef FEAT_DIFF
  1586.     if (lp->fill < diff_check_fill(curwin, lp->lnum + 1))
  1587.     {
  1588.     /* Add a filler line. */
  1589.     ++lp->fill;
  1590.     lp->height = 1;
  1591.     }
  1592.     else
  1593. #endif
  1594.     {
  1595.     ++lp->lnum;
  1596. #ifdef FEAT_DIFF
  1597.     lp->fill = 0;
  1598. #endif
  1599.     if (lp->lnum > curbuf->b_ml.ml_line_count)
  1600.         lp->height = MAXCOL;
  1601.     else
  1602. #ifdef FEAT_FOLDING
  1603.         if (hasFolding(lp->lnum, NULL, &lp->lnum))
  1604.         /* Add a closed fold */
  1605.         lp->height = 1;
  1606.     else
  1607. #endif
  1608.     {
  1609. #ifdef FEAT_DIFF
  1610.         lp->height = plines_nofill(lp->lnum);
  1611. #else
  1612.         lp->height = plines(lp->lnum);
  1613. #endif
  1614.     }
  1615.     }
  1616. }
  1617.  
  1618. #ifdef FEAT_DIFF
  1619. /*
  1620.  * Switch from including filler lines below lp->lnum to including filler
  1621.  * lines above loff.lnum + 1.  This keeps pointing to the same line.
  1622.  * When there are no filler lines nothing changes.
  1623.  */
  1624.     static void
  1625. botline_topline(lp)
  1626.     lineoff_T    *lp;
  1627. {
  1628.     if (lp->fill > 0)
  1629.     {
  1630.     ++lp->lnum;
  1631.     lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
  1632.     }
  1633. }
  1634.  
  1635. /*
  1636.  * Switch from including filler lines above lp->lnum to including filler
  1637.  * lines below loff.lnum - 1.  This keeps pointing to the same line.
  1638.  * When there are no filler lines nothing changes.
  1639.  */
  1640.     static void
  1641. topline_botline(lp)
  1642.     lineoff_T    *lp;
  1643. {
  1644.     if (lp->fill > 0)
  1645.     {
  1646.     lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
  1647.     --lp->lnum;
  1648.     }
  1649. }
  1650. #endif
  1651.  
  1652. /*
  1653.  * Recompute topline to put the cursor at the top of the window.
  1654.  * Scroll at least "min_scroll" lines.
  1655.  * If "always" is TRUE, always set topline (for "zt").
  1656.  */
  1657.     void
  1658. scroll_cursor_top(min_scroll, always)
  1659.     int        min_scroll;
  1660.     int        always;
  1661. {
  1662.     int        scrolled = 0;
  1663.     int        extra = 0;
  1664.     int        used;
  1665.     int        i;
  1666.     linenr_T    top;        /* just above displayed lines */
  1667.     linenr_T    bot;        /* just below displayed lines */
  1668.     linenr_T    old_topline = curwin->w_topline;
  1669. #ifdef FEAT_DIFF
  1670.     linenr_T    old_topfill = curwin->w_topfill;
  1671. #endif
  1672.     linenr_T    new_topline;
  1673.     int        off = p_so;
  1674.  
  1675. #ifdef FEAT_MOUSE
  1676.     if (mouse_dragging > 0)
  1677.     off = mouse_dragging - 1;
  1678. #endif
  1679.  
  1680.     /*
  1681.      * Decrease topline until:
  1682.      * - it has become 1
  1683.      * - (part of) the cursor line is moved off the screen or
  1684.      * - moved at least 'scrolljump' lines and
  1685.      * - at least 'scrolloff' lines above and below the cursor
  1686.      */
  1687.     validate_cheight();
  1688.     used = curwin->w_cline_height;
  1689.     if (curwin->w_cursor.lnum < curwin->w_topline)
  1690.     scrolled = used;
  1691.  
  1692. #ifdef FEAT_FOLDING
  1693.     if (hasFolding(curwin->w_cursor.lnum, &top, &bot))
  1694.     {
  1695.     --top;
  1696.     ++bot;
  1697.     }
  1698.     else
  1699. #endif
  1700.     {
  1701.     top = curwin->w_cursor.lnum - 1;
  1702.     bot = curwin->w_cursor.lnum + 1;
  1703.     }
  1704.     new_topline = top + 1;
  1705.  
  1706. #ifdef FEAT_DIFF
  1707.     /* count filler lines of the cursor window as context */
  1708.     i = diff_check_fill(curwin, curwin->w_cursor.lnum);
  1709.     used += i;
  1710.     extra += i;
  1711. #endif
  1712.  
  1713.     /*
  1714.      * Check if the lines from "top" to "bot" fit in the window.  If they do,
  1715.      * set new_topline and advance "top" and "bot" to include more lines.
  1716.      */
  1717.     while (top > 0)
  1718.     {
  1719. #ifdef FEAT_FOLDING
  1720.     if (hasFolding(top, &top, NULL))
  1721.         /* count one logical line for a sequence of folded lines */
  1722.         i = 1;
  1723.     else
  1724. #endif
  1725.         i = plines(top);
  1726.     used += i;
  1727.     if (extra + i <= off && bot < curbuf->b_ml.ml_line_count)
  1728.     {
  1729. #ifdef FEAT_FOLDING
  1730.         if (hasFolding(bot, NULL, &bot))
  1731.         /* count one logical line for a sequence of folded lines */
  1732.         ++used;
  1733.         else
  1734. #endif
  1735.         used += plines(bot);
  1736.     }
  1737.     if (used > curwin->w_height)
  1738.         break;
  1739.     if (top < curwin->w_topline)
  1740.         scrolled += i;
  1741.  
  1742.     /*
  1743.      * If scrolling is needed, scroll at least 'sj' lines.
  1744.      */
  1745.     if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
  1746.         && extra >= off)
  1747.         break;
  1748.  
  1749.     extra += i;
  1750.     new_topline = top;
  1751.     --top;
  1752.     ++bot;
  1753.     }
  1754.  
  1755.     /*
  1756.      * If we don't have enough space, put cursor in the middle.
  1757.      * This makes sure we get the same position when using "k" and "j"
  1758.      * in a small window.
  1759.      */
  1760.     if (used > curwin->w_height)
  1761.     scroll_cursor_halfway(FALSE);
  1762.     else
  1763.     {
  1764.     /*
  1765.      * If "always" is FALSE, only adjust topline to a lower value, higher
  1766.      * value may happen with wrapping lines
  1767.      */
  1768.     if (new_topline < curwin->w_topline || always)
  1769.         curwin->w_topline = new_topline;
  1770.     if (curwin->w_topline > curwin->w_cursor.lnum)
  1771.         curwin->w_topline = curwin->w_cursor.lnum;
  1772. #ifdef FEAT_DIFF
  1773.     curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
  1774.     if (curwin->w_topfill > 0 && extra > off)
  1775.     {
  1776.         curwin->w_topfill -= extra - off;
  1777.         if (curwin->w_topfill < 0)
  1778.         curwin->w_topfill = 0;
  1779.     }
  1780.     check_topfill(curwin, FALSE);
  1781. #endif
  1782.     if (curwin->w_topline != old_topline
  1783. #ifdef FEAT_DIFF
  1784.         || curwin->w_topfill != old_topfill
  1785. #endif
  1786.         )
  1787.         curwin->w_valid &=
  1788.               ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  1789.     curwin->w_valid |= VALID_TOPLINE;
  1790.     }
  1791. }
  1792.  
  1793. /*
  1794.  * Set w_empty_rows and w_filler_rows for window "wp", having used up "used"
  1795.  * screen lines for text lines.
  1796.  */
  1797.     void
  1798. set_empty_rows(wp, used)
  1799.     win_T    *wp;
  1800.     int        used;
  1801. {
  1802. #ifdef FEAT_DIFF
  1803.     wp->w_filler_rows = 0;
  1804. #endif
  1805.     if (used == 0)
  1806.     wp->w_empty_rows = 0;    /* single line that doesn't fit */
  1807.     else
  1808.     {
  1809.     wp->w_empty_rows = wp->w_height - used;
  1810. #ifdef FEAT_DIFF
  1811.     if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count)
  1812.     {
  1813.         wp->w_filler_rows = diff_check_fill(wp, wp->w_botline);
  1814.         if (wp->w_empty_rows > wp->w_filler_rows)
  1815.         wp->w_empty_rows -= wp->w_filler_rows;
  1816.         else
  1817.         {
  1818.         wp->w_filler_rows = wp->w_empty_rows;
  1819.         wp->w_empty_rows = 0;
  1820.         }
  1821.     }
  1822. #endif
  1823.     }
  1824. }
  1825.  
  1826. /*
  1827.  * Recompute topline to put the cursor at the bottom of the window.
  1828.  * Scroll at least "min_scroll" lines.
  1829.  * If "set_topbot" is TRUE, set topline and botline first (for "zb").
  1830.  * This is messy stuff!!!
  1831.  */
  1832.     void
  1833. scroll_cursor_bot(min_scroll, set_topbot)
  1834.     int        min_scroll;
  1835.     int        set_topbot;
  1836. {
  1837.     int        used;
  1838.     int        scrolled = 0;
  1839.     int        extra = 0;
  1840.     int        i;
  1841.     linenr_T    line_count;
  1842.     linenr_T    old_topline = curwin->w_topline;
  1843.     lineoff_T    loff;
  1844.     lineoff_T    boff;
  1845. #ifdef FEAT_DIFF
  1846.     int        old_topfill = curwin->w_topfill;
  1847.     int        fill_below_window;
  1848. #endif
  1849.     linenr_T    old_botline = curwin->w_botline;
  1850.     linenr_T    old_valid = curwin->w_valid;
  1851.     int        old_empty_rows = curwin->w_empty_rows;
  1852.     linenr_T    cln;            /* Cursor Line Number */
  1853.  
  1854.     cln = curwin->w_cursor.lnum;
  1855.     if (set_topbot)
  1856.     {
  1857.     used = 0;
  1858.     curwin->w_botline = cln + 1;
  1859. #ifdef FEAT_DIFF
  1860.     loff.fill = 0;
  1861. #endif
  1862.     for (curwin->w_topline = curwin->w_botline;
  1863.         curwin->w_topline > 1;
  1864.         curwin->w_topline = loff.lnum)
  1865.     {
  1866.         loff.lnum = curwin->w_topline;
  1867.         topline_back(&loff);
  1868.         if (used + loff.height > curwin->w_height)
  1869.         break;
  1870.         used += loff.height;
  1871. #ifdef FEAT_DIFF
  1872.         curwin->w_topfill = loff.fill;
  1873. #endif
  1874.     }
  1875.     set_empty_rows(curwin, used);
  1876.     curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  1877.     if (curwin->w_topline != old_topline
  1878. #ifdef FEAT_DIFF
  1879.         || curwin->w_topfill != old_topfill
  1880. #endif
  1881.         )
  1882.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
  1883.     }
  1884.     else
  1885.     validate_botline();
  1886.  
  1887.     /* The lines of the cursor line itself are always used. */
  1888. #ifdef FEAT_DIFF
  1889.     used = plines_nofill(cln);
  1890. #else
  1891.     validate_cheight();
  1892.     used = curwin->w_cline_height;
  1893. #endif
  1894.  
  1895.     /* If the cursor is below botline, we will at least scroll by the height
  1896.      * of the cursor line.  Correct for empty lines, which are really part of
  1897.      * botline. */
  1898.     if (cln >= curwin->w_botline)
  1899.     {
  1900.     scrolled = used;
  1901.     if (cln == curwin->w_botline)
  1902.         scrolled -= curwin->w_empty_rows;
  1903.     }
  1904.  
  1905.     /*
  1906.      * Stop counting lines to scroll when
  1907.      * - hitting start of the file
  1908.      * - scrolled nothing or at least 'sj' lines
  1909.      * - at least 'so' lines below the cursor
  1910.      * - lines between botline and cursor have been counted
  1911.      */
  1912. #ifdef FEAT_FOLDING
  1913.     if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum))
  1914. #endif
  1915.     {
  1916.     loff.lnum = cln;
  1917.     boff.lnum = cln;
  1918.     }
  1919. #ifdef FEAT_DIFF
  1920.     loff.fill = 0;
  1921.     boff.fill = 0;
  1922.     fill_below_window = diff_check_fill(curwin, curwin->w_botline)
  1923.                               - curwin->w_filler_rows;
  1924. #endif
  1925.  
  1926.     while (loff.lnum > 1)
  1927.     {
  1928.     /* Stop when scrolled nothing or at least "min_scroll", found "extra"
  1929.      * context for 'scrolloff' and counted all lines below the window. */
  1930.     if ((((scrolled <= 0 || scrolled >= min_scroll)
  1931.             && extra >= (
  1932. #ifdef FEAT_MOUSE
  1933.                 mouse_dragging ? mouse_dragging - 1 :
  1934. #endif
  1935.                 p_so))
  1936.             || boff.lnum + 1 > curbuf->b_ml.ml_line_count)
  1937.         && loff.lnum <= curwin->w_botline
  1938. #ifdef FEAT_DIFF
  1939.         && (loff.lnum < curwin->w_botline
  1940.             || loff.fill >= fill_below_window)
  1941. #endif
  1942.         )
  1943.         break;
  1944.  
  1945.     /* Add one line above */
  1946.     topline_back(&loff);
  1947.     used += loff.height;
  1948.     if (used > curwin->w_height)
  1949.         break;
  1950.     if (loff.lnum >= curwin->w_botline
  1951. #ifdef FEAT_DIFF
  1952.         && (loff.lnum > curwin->w_botline
  1953.             || loff.fill <= fill_below_window)
  1954. #endif
  1955.         )
  1956.     {
  1957.         /* Count screen lines that are below the window. */
  1958.         scrolled += loff.height;
  1959.         if (loff.lnum == curwin->w_botline
  1960. #ifdef FEAT_DIFF
  1961.                 && boff.fill == 0
  1962. #endif
  1963.             )
  1964.         scrolled -= curwin->w_empty_rows;
  1965.     }
  1966.  
  1967.     if (boff.lnum < curbuf->b_ml.ml_line_count)
  1968.     {
  1969.         /* Add one line below */
  1970.         botline_forw(&boff);
  1971.         used += boff.height;
  1972.         if (used > curwin->w_height)
  1973.         break;
  1974.         if (extra < (
  1975. #ifdef FEAT_MOUSE
  1976.             mouse_dragging > 0 ? mouse_dragging - 1 :
  1977. #endif
  1978.             p_so) || scrolled < min_scroll)
  1979.         {
  1980.         extra += boff.height;
  1981.         if (boff.lnum >= curwin->w_botline
  1982. #ifdef FEAT_DIFF
  1983.             || (boff.lnum + 1 == curwin->w_botline
  1984.                 && boff.fill > curwin->w_filler_rows)
  1985. #endif
  1986.            )
  1987.         {
  1988.             /* Count screen lines that are below the window. */
  1989.             scrolled += boff.height;
  1990.             if (boff.lnum == curwin->w_botline
  1991. #ifdef FEAT_DIFF
  1992.                 && boff.fill == 0
  1993. #endif
  1994.                 )
  1995.             scrolled -= curwin->w_empty_rows;
  1996.         }
  1997.         }
  1998.     }
  1999.     }
  2000.  
  2001.     /* curwin->w_empty_rows is larger, no need to scroll */
  2002.     if (scrolled <= 0)
  2003.     line_count = 0;
  2004.     /* more than a screenfull, don't scroll but redraw */
  2005.     else if (used > curwin->w_height)
  2006.     line_count = used;
  2007.     /* scroll minimal number of lines */
  2008.     else
  2009.     {
  2010.     line_count = 0;
  2011. #ifdef FEAT_DIFF
  2012.     boff.fill = curwin->w_topfill;
  2013. #endif
  2014.     boff.lnum = curwin->w_topline - 1;
  2015.     for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; )
  2016.     {
  2017.         botline_forw(&boff);
  2018.         i += boff.height;
  2019.         ++line_count;
  2020.     }
  2021.     if (i < scrolled)    /* below curwin->w_botline, don't scroll */
  2022.         line_count = 9999;
  2023.     }
  2024.  
  2025.     /*
  2026.      * Scroll up if the cursor is off the bottom of the screen a bit.
  2027.      * Otherwise put it at 1/2 of the screen.
  2028.      */
  2029.     if (line_count >= curwin->w_height && line_count > min_scroll)
  2030.     scroll_cursor_halfway(FALSE);
  2031.     else
  2032.     scrollup(line_count, TRUE);
  2033.  
  2034.     /*
  2035.      * If topline didn't change we need to restore w_botline and w_empty_rows
  2036.      * (we changed them).
  2037.      * If topline did change, update_screen() will set botline.
  2038.      */
  2039.     if (curwin->w_topline == old_topline && set_topbot)
  2040.     {
  2041.     curwin->w_botline = old_botline;
  2042.     curwin->w_empty_rows = old_empty_rows;
  2043.     curwin->w_valid = old_valid;
  2044.     }
  2045.     curwin->w_valid |= VALID_TOPLINE;
  2046. }
  2047.  
  2048. /*
  2049.  * Recompute topline to put the cursor halfway the window
  2050.  * If "atend" is TRUE, also put it halfway at the end of the file.
  2051.  */
  2052.     void
  2053. scroll_cursor_halfway(atend)
  2054.     int        atend;
  2055. {
  2056.     int        above = 0;
  2057.     linenr_T    topline;
  2058. #ifdef FEAT_DIFF
  2059.     int        topfill = 0;
  2060. #endif
  2061.     int        below = 0;
  2062.     int        used;
  2063.     lineoff_T    loff;
  2064.     lineoff_T    boff;
  2065.  
  2066.     loff.lnum = boff.lnum = curwin->w_cursor.lnum;
  2067. #ifdef FEAT_DIFF
  2068.     used = plines_nofill(loff.lnum);
  2069.     loff.fill = 0;
  2070.     boff.fill = 0;
  2071. #else
  2072.     used = plines(loff.lnum);
  2073. #endif
  2074.     topline = loff.lnum;
  2075.     while (topline > 1)
  2076.     {
  2077.     if (below <= above)        /* add a line below the cursor first */
  2078.     {
  2079.         if (boff.lnum < curbuf->b_ml.ml_line_count)
  2080.         {
  2081.         botline_forw(&boff);
  2082.         used += boff.height;
  2083.         if (used > curwin->w_height)
  2084.             break;
  2085.         below += boff.height;
  2086.         }
  2087.         else
  2088.         {
  2089.         ++below;        /* count a "~" line */
  2090.         if (atend)
  2091.             ++used;
  2092.         }
  2093.     }
  2094.  
  2095.     if (below > above)        /* add a line above the cursor */
  2096.     {
  2097.         topline_back(&loff);
  2098.         used += loff.height;
  2099.         if (used > curwin->w_height)
  2100.         break;
  2101.         above += loff.height;
  2102.         topline = loff.lnum;
  2103. #ifdef FEAT_DIFF
  2104.         topfill = loff.fill;
  2105. #endif
  2106.     }
  2107.     }
  2108. #ifdef FEAT_FOLDING
  2109.     if (!hasFolding(topline, &curwin->w_topline, NULL))
  2110. #endif
  2111.     curwin->w_topline = topline;
  2112. #ifdef FEAT_DIFF
  2113.     curwin->w_topfill = topfill;
  2114.     check_topfill(curwin, FALSE);
  2115. #endif
  2116.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2117.     curwin->w_valid |= VALID_TOPLINE;
  2118. }
  2119.  
  2120. /*
  2121.  * Correct the cursor position so that it is in a part of the screen at least
  2122.  * 'so' lines from the top and bottom, if possible.
  2123.  * If not possible, put it at the same position as scroll_cursor_halfway().
  2124.  * When called topline must be valid!
  2125.  */
  2126.     void
  2127. cursor_correct()
  2128. {
  2129.     int        above = 0;        /* screen lines above topline */
  2130.     linenr_T    topline;
  2131.     int        below = 0;        /* screen lines below botline */
  2132.     linenr_T    botline;
  2133.     int        above_wanted, below_wanted;
  2134.     linenr_T    cln;            /* Cursor Line Number */
  2135.     int        max_off;
  2136.  
  2137.     /*
  2138.      * How many lines we would like to have above/below the cursor depends on
  2139.      * whether the first/last line of the file is on screen.
  2140.      */
  2141.     above_wanted = p_so;
  2142.     below_wanted = p_so;
  2143. #ifdef FEAT_MOUSE
  2144.     if (mouse_dragging)
  2145.     {
  2146.     above_wanted = mouse_dragging - 1;
  2147.     below_wanted = mouse_dragging - 1;
  2148.     }
  2149. #endif
  2150.     if (curwin->w_topline == 1)
  2151.     {
  2152.     above_wanted = 0;
  2153.     max_off = curwin->w_height / 2;
  2154.     if (below_wanted > max_off)
  2155.         below_wanted = max_off;
  2156.     }
  2157.     validate_botline();
  2158.     if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1
  2159. #ifdef FEAT_MOUSE
  2160.         && !mouse_dragging
  2161. #endif
  2162.         )
  2163.     {
  2164.     below_wanted = 0;
  2165.     max_off = (curwin->w_height - 1) / 2;
  2166.     if (above_wanted > max_off)
  2167.         above_wanted = max_off;
  2168.     }
  2169.  
  2170.     /*
  2171.      * If there are sufficient file-lines above and below the cursor, we can
  2172.      * return now.
  2173.      */
  2174.     cln = curwin->w_cursor.lnum;
  2175.     if (cln >= curwin->w_topline + above_wanted
  2176.         && cln < curwin->w_botline - below_wanted
  2177. #ifdef FEAT_FOLDING
  2178.         && !hasAnyFolding(curwin)
  2179. #endif
  2180.         )
  2181.     return;
  2182.  
  2183.     /*
  2184.      * Narrow down the area where the cursor can be put by taking lines from
  2185.      * the top and the bottom until:
  2186.      * - the desired context lines are found
  2187.      * - the lines from the top is past the lines from the bottom
  2188.      */
  2189.     topline = curwin->w_topline;
  2190.     botline = curwin->w_botline - 1;
  2191. #ifdef FEAT_DIFF
  2192.     /* count filler lines as context */
  2193.     above = curwin->w_topfill;
  2194.     below = curwin->w_filler_rows;
  2195. #endif
  2196.     while ((above < above_wanted || below < below_wanted) && topline < botline)
  2197.     {
  2198.     if (below < below_wanted && (below <= above || above >= above_wanted))
  2199.     {
  2200. #ifdef FEAT_FOLDING
  2201.         if (hasFolding(botline, &botline, NULL))
  2202.         ++below;
  2203.         else
  2204. #endif
  2205.         below += plines(botline);
  2206.         --botline;
  2207.     }
  2208.     if (above < above_wanted && (above < below || below >= below_wanted))
  2209.     {
  2210. #ifdef FEAT_FOLDING
  2211.         if (hasFolding(topline, NULL, &topline))
  2212.         ++above;
  2213.         else
  2214. #endif
  2215. #ifndef FEAT_DIFF
  2216.         above += plines(topline);
  2217. #else
  2218.         above += plines_nofill(topline);
  2219.  
  2220.         /* Count filler lines below this line as context. */
  2221.         if (topline < botline)
  2222.         above += diff_check_fill(curwin, topline + 1);
  2223. #endif
  2224.         ++topline;
  2225.     }
  2226.     }
  2227.     if (topline == botline || botline == 0)
  2228.     curwin->w_cursor.lnum = topline;
  2229.     else if (topline > botline)
  2230.     curwin->w_cursor.lnum = botline;
  2231.     else
  2232.     {
  2233.     if (cln < topline && curwin->w_topline > 1)
  2234.     {
  2235.         curwin->w_cursor.lnum = topline;
  2236.         curwin->w_valid &=
  2237.                 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
  2238.     }
  2239.     if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  2240.     {
  2241.         curwin->w_cursor.lnum = botline;
  2242.         curwin->w_valid &=
  2243.                 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
  2244.     }
  2245.     }
  2246.     curwin->w_valid |= VALID_TOPLINE;
  2247. }
  2248.  
  2249. static void get_scroll_overlap __ARGS((lineoff_T *lp, int dir));
  2250.  
  2251. /*
  2252.  * move screen 'count' pages up or down and update screen
  2253.  *
  2254.  * return FAIL for failure, OK otherwise
  2255.  */
  2256.     int
  2257. onepage(dir, count)
  2258.     int        dir;
  2259.     long    count;
  2260. {
  2261.     long    n;
  2262.     int        retval = OK;
  2263.     lineoff_T    loff;
  2264.  
  2265.     if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
  2266.     {
  2267.     beep_flush();
  2268.     return FAIL;
  2269.     }
  2270.  
  2271.     for ( ; count > 0; --count)
  2272.     {
  2273.     validate_botline();
  2274.     /*
  2275.      * It's an error to move a page up when the first line is already on
  2276.      * the screen.    It's an error to move a page down when the last line
  2277.      * is on the screen and the topline is 'scrolloff' lines from the
  2278.      * last line.
  2279.      */
  2280.     if (dir == FORWARD
  2281.         ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so)
  2282.             && curwin->w_botline > curbuf->b_ml.ml_line_count)
  2283.         : (curwin->w_topline == 1
  2284. #ifdef FEAT_DIFF
  2285.             && curwin->w_topfill ==
  2286.                     diff_check_fill(curwin, curwin->w_topline)
  2287. #endif
  2288.             ))
  2289.     {
  2290.         beep_flush();
  2291.         retval = FAIL;
  2292.         break;
  2293.     }
  2294.  
  2295. #ifdef FEAT_DIFF
  2296.     loff.fill = 0;
  2297. #endif
  2298.     if (dir == FORWARD)
  2299.     {
  2300.                     /* at end of file */
  2301.         if (curwin->w_botline > curbuf->b_ml.ml_line_count)
  2302.         {
  2303.         curwin->w_topline = curbuf->b_ml.ml_line_count;
  2304. #ifdef FEAT_DIFF
  2305.         curwin->w_topfill = 0;
  2306. #endif
  2307.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
  2308.         }
  2309.         else
  2310.         {
  2311.         /* For the overlap, start with the line just below the window
  2312.          * and go upwards. */
  2313.         loff.lnum = curwin->w_botline;
  2314. #ifdef FEAT_DIFF
  2315.         loff.fill = diff_check_fill(curwin, loff.lnum)
  2316.                               - curwin->w_filler_rows;
  2317. #endif
  2318.         get_scroll_overlap(&loff, -1);
  2319.         curwin->w_topline = loff.lnum;
  2320. #ifdef FEAT_DIFF
  2321.         curwin->w_topfill = loff.fill;
  2322.         check_topfill(curwin, FALSE);
  2323. #endif
  2324.         curwin->w_cursor.lnum = curwin->w_topline;
  2325.         curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
  2326.                    VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2327.         }
  2328.     }
  2329.     else    /* dir == BACKWARDS */
  2330.     {
  2331. #ifdef FEAT_DIFF
  2332.         if (curwin->w_topline == 1)
  2333.         {
  2334.         /* Include max number of filler lines */
  2335.         max_topfill();
  2336.         continue;
  2337.         }
  2338. #endif
  2339.         /* Find the line at the top of the window that is going to be the
  2340.          * line at the bottom of the window.  Make sure this results in
  2341.          * the same line as before doing CTRL-F. */
  2342.         loff.lnum = curwin->w_topline - 1;
  2343. #ifdef FEAT_DIFF
  2344.         loff.fill = diff_check_fill(curwin, loff.lnum + 1)
  2345.                               - curwin->w_topfill;
  2346. #endif
  2347.         get_scroll_overlap(&loff, 1);
  2348.  
  2349.         if (loff.lnum >= curbuf->b_ml.ml_line_count)
  2350.         {
  2351.         loff.lnum = curbuf->b_ml.ml_line_count;
  2352. #ifdef FEAT_DIFF
  2353.         loff.fill = 0;
  2354.         }
  2355.         else
  2356.         {
  2357.         botline_topline(&loff);
  2358. #endif
  2359.         }
  2360.         curwin->w_cursor.lnum = loff.lnum;
  2361.  
  2362.         /* Find the line just above the new topline to get the right line
  2363.          * at the bottom of the window. */
  2364.         n = 0;
  2365.         while (n <= curwin->w_height && loff.lnum >= 1)
  2366.         {
  2367.         topline_back(&loff);
  2368.         n += loff.height;
  2369.         }
  2370.         if (n <= curwin->w_height)            /* at begin of file */
  2371.         {
  2372.         curwin->w_topline = 1;
  2373. #ifdef FEAT_DIFF
  2374.         max_topfill();
  2375. #endif
  2376.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  2377.         }
  2378.         else
  2379.         {
  2380.         /* Go two lines forward again. */
  2381. #ifdef FEAT_DIFF
  2382.         topline_botline(&loff);
  2383. #endif
  2384.         botline_forw(&loff);
  2385.         botline_forw(&loff);
  2386. #ifdef FEAT_DIFF
  2387.         botline_topline(&loff);
  2388. #endif
  2389. #ifdef FEAT_FOLDING
  2390.         /* We're at the wrong end of a fold now. */
  2391.         (void)hasFolding(loff.lnum, &loff.lnum, NULL);
  2392. #endif
  2393.  
  2394.         /* Always scroll at least one line.  Avoid getting stuck on
  2395.          * very long lines. */
  2396.         if (loff.lnum >= curwin->w_topline
  2397. #ifdef FEAT_DIFF
  2398.             && (loff.lnum > curwin->w_topline
  2399.                 || loff.fill >= curwin->w_topfill)
  2400. #endif
  2401.             )
  2402.         {
  2403. #ifdef FEAT_DIFF
  2404.             /* First try using the maximum number of filler lines.  If
  2405.              * that's not enough, backup one line. */
  2406.             loff.fill = curwin->w_topfill;
  2407.             if (curwin->w_topfill < diff_check_fill(curwin,
  2408.                                curwin->w_topline))
  2409.             max_topfill();
  2410.             if (curwin->w_topfill == loff.fill)
  2411. #endif
  2412.             {
  2413.             --curwin->w_topline;
  2414. #ifdef FEAT_DIFF
  2415.             curwin->w_topfill = 0;
  2416. #endif
  2417.             }
  2418.             comp_botline(curwin);
  2419.             curwin->w_cursor.lnum = curwin->w_botline - 1;
  2420.             curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|
  2421.                 VALID_WROW|VALID_CROW);
  2422.         }
  2423.         else
  2424.         {
  2425.             curwin->w_topline = loff.lnum;
  2426. #ifdef FEAT_DIFF
  2427.             curwin->w_topfill = loff.fill;
  2428.             check_topfill(curwin, FALSE);
  2429. #endif
  2430.             curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  2431.         }
  2432.         }
  2433.     }
  2434.     }
  2435. #ifdef FEAT_FOLDING
  2436.     foldAdjustCursor();
  2437. #endif
  2438.     cursor_correct();
  2439.     beginline(BL_SOL | BL_FIX);
  2440.     curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
  2441.  
  2442.     /*
  2443.      * Avoid the screen jumping up and down when 'scrolloff' is non-zero.
  2444.      */
  2445.     if (dir == FORWARD && check_top_offset())
  2446.     scroll_cursor_top(1, FALSE);
  2447.  
  2448.     redraw_later(VALID);
  2449.     return retval;
  2450. }
  2451.  
  2452. /*
  2453.  * Decide how much overlap to use for page-up or page-down scrolling.
  2454.  * This is symmetric, so that doing both keeps the same lines displayed.
  2455.  * Three lines are examined:
  2456.  *
  2457.  *  before CTRL-F        after CTRL-F / before CTRL-B
  2458.  *     etc.            l1
  2459.  *  l1 last but one line    ------------
  2460.  *  l2 last text line        l2 top text line
  2461.  *  -------------        l3 second text line
  2462.  *  l3                   etc.
  2463.  */
  2464.     static void
  2465. get_scroll_overlap(lp, dir)
  2466.     lineoff_T    *lp;
  2467.     int        dir;
  2468. {
  2469.     int        h1, h2, h3, h4;
  2470.     int        min_height = curwin->w_height - 2;
  2471.     lineoff_T    loff0, loff1, loff2;
  2472.  
  2473. #ifdef FEAT_DIFF
  2474.     if (lp->fill > 0)
  2475.     lp->height = 1;
  2476.     else
  2477.     lp->height = plines_nofill(lp->lnum);
  2478. #else
  2479.     lp->height = plines(lp->lnum);
  2480. #endif
  2481.     h1 = lp->height;
  2482.     if (h1 > min_height)
  2483.     return;        /* no overlap */
  2484.  
  2485.     loff0 = *lp;
  2486.     if (dir > 0)
  2487.     botline_forw(lp);
  2488.     else
  2489.     topline_back(lp);
  2490.     h2 = lp->height;
  2491.     if (h2 + h1 > min_height)
  2492.     {
  2493.     *lp = loff0;    /* no overlap */
  2494.     return;
  2495.     }
  2496.  
  2497.     loff1 = *lp;
  2498.     if (dir > 0)
  2499.     botline_forw(lp);
  2500.     else
  2501.     topline_back(lp);
  2502.     h3 = lp->height;
  2503.     if (h3 + h2 > min_height)
  2504.     {
  2505.     *lp = loff0;    /* no overlap */
  2506.     return;
  2507.     }
  2508.  
  2509.     loff2 = *lp;
  2510.     if (dir > 0)
  2511.     botline_forw(lp);
  2512.     else
  2513.     topline_back(lp);
  2514.     h4 = lp->height;
  2515.     if (h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
  2516.     *lp = loff1;    /* 1 line overlap */
  2517.     else
  2518.     *lp = loff2;    /* 2 lines overlap */
  2519.     return;
  2520. }
  2521.  
  2522. /* #define KEEP_SCREEN_LINE */
  2523. /*
  2524.  * Scroll 'scroll' lines up or down.
  2525.  */
  2526.     void
  2527. halfpage(flag, Prenum)
  2528.     int        flag;
  2529.     linenr_T    Prenum;
  2530. {
  2531.     long    scrolled = 0;
  2532.     int        i;
  2533.     int        n;
  2534.     int        room;
  2535.  
  2536.     if (Prenum)
  2537.     curwin->w_p_scr = (Prenum > curwin->w_height) ?
  2538.                         curwin->w_height : Prenum;
  2539.     n = (curwin->w_p_scr <= curwin->w_height) ?
  2540.                     curwin->w_p_scr : curwin->w_height;
  2541.  
  2542.     validate_botline();
  2543.     room = curwin->w_empty_rows;
  2544. #ifdef FEAT_DIFF
  2545.     room += curwin->w_filler_rows;
  2546. #endif
  2547.     if (flag)
  2548.     {
  2549.     /*
  2550.      * scroll the text up
  2551.      */
  2552.     while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  2553.     {
  2554. #ifdef FEAT_DIFF
  2555.         if (curwin->w_topfill > 0)
  2556.         {
  2557.         i = 1;
  2558.         if (--n < 0 && scrolled > 0)
  2559.             break;
  2560.         --curwin->w_topfill;
  2561.         }
  2562.         else
  2563. #endif
  2564.         {
  2565. #ifdef FEAT_DIFF
  2566.         i = plines_nofill(curwin->w_topline);
  2567. #else
  2568.         i = plines(curwin->w_topline);
  2569. #endif
  2570.         n -= i;
  2571.         if (n < 0 && scrolled > 0)
  2572.             break;
  2573. #ifdef FEAT_FOLDING
  2574.         (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
  2575. #endif
  2576.         ++curwin->w_topline;
  2577. #ifdef FEAT_DIFF
  2578.         curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
  2579. #endif
  2580.  
  2581. #ifndef KEEP_SCREEN_LINE
  2582.         if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  2583.         {
  2584.             ++curwin->w_cursor.lnum;
  2585.             curwin->w_valid &=
  2586.                     ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
  2587.         }
  2588. #endif
  2589.         }
  2590.         curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
  2591.         scrolled += i;
  2592.  
  2593.         /*
  2594.          * Correct w_botline for changed w_topline.
  2595.          * Won't work when there are filler lines.
  2596.          */
  2597. #ifdef FEAT_DIFF
  2598.         if (curwin->w_p_diff)
  2599.         curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  2600.         else
  2601. #endif
  2602.         {
  2603.         room += i;
  2604.         do
  2605.         {
  2606.             i = plines(curwin->w_botline);
  2607.             if (i > room)
  2608.             break;
  2609. #ifdef FEAT_FOLDING
  2610.             (void)hasFolding(curwin->w_botline, NULL,
  2611.                               &curwin->w_botline);
  2612. #endif
  2613.             ++curwin->w_botline;
  2614.             room -= i;
  2615.         } while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
  2616.         }
  2617.     }
  2618.  
  2619. #ifndef KEEP_SCREEN_LINE
  2620.     /*
  2621.      * When hit bottom of the file: move cursor down.
  2622.      */
  2623.     if (n > 0)
  2624.     {
  2625. # ifdef FEAT_FOLDING
  2626.         if (hasAnyFolding(curwin))
  2627.         {
  2628.         while (--n >= 0
  2629.             && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  2630.         {
  2631.             (void)hasFolding(curwin->w_cursor.lnum, NULL,
  2632.                               &curwin->w_cursor.lnum);
  2633.             ++curwin->w_cursor.lnum;
  2634.         }
  2635.         }
  2636.         else
  2637. # endif
  2638.         curwin->w_cursor.lnum += n;
  2639.         check_cursor_lnum();
  2640.     }
  2641. #else
  2642.     /* try to put the cursor in the same screen line */
  2643.     while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
  2644.                  && curwin->w_cursor.lnum < curwin->w_botline - 1)
  2645.     {
  2646.         scrolled -= plines(curwin->w_cursor.lnum);
  2647.         if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
  2648.         break;
  2649. # ifdef FEAT_FOLDING
  2650.         (void)hasFolding(curwin->w_cursor.lnum, NULL,
  2651.                               &curwin->w_cursor.lnum);
  2652. # endif
  2653.         ++curwin->w_cursor.lnum;
  2654.     }
  2655. #endif
  2656.     }
  2657.     else
  2658.     {
  2659.     /*
  2660.      * scroll the text down
  2661.      */
  2662.     while (n > 0 && curwin->w_topline > 1)
  2663.     {
  2664. #ifdef FEAT_DIFF
  2665.         if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline))
  2666.         {
  2667.         i = 1;
  2668.         if (--n < 0 && scrolled > 0)
  2669.             break;
  2670.         ++curwin->w_topfill;
  2671.         }
  2672.         else
  2673. #endif
  2674.         {
  2675. #ifdef FEAT_DIFF
  2676.         i = plines_nofill(curwin->w_topline - 1);
  2677. #else
  2678.         i = plines(curwin->w_topline - 1);
  2679. #endif
  2680.         n -= i;
  2681.         if (n < 0 && scrolled > 0)
  2682.             break;
  2683.         --curwin->w_topline;
  2684. #ifdef FEAT_FOLDING
  2685.         (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  2686. #endif
  2687. #ifdef FEAT_DIFF
  2688.         curwin->w_topfill = 0;
  2689. #endif
  2690.         }
  2691.         curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
  2692.                           VALID_BOTLINE|VALID_BOTLINE_AP);
  2693.         scrolled += i;
  2694. #ifndef KEEP_SCREEN_LINE
  2695.         if (curwin->w_cursor.lnum > 1)
  2696.         {
  2697.         --curwin->w_cursor.lnum;
  2698.         curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
  2699.         }
  2700. #endif
  2701.     }
  2702. #ifndef KEEP_SCREEN_LINE
  2703.     /*
  2704.      * When hit top of the file: move cursor up.
  2705.      */
  2706.     if (n > 0)
  2707.     {
  2708.         if (curwin->w_cursor.lnum <= (linenr_T)n)
  2709.         curwin->w_cursor.lnum = 1;
  2710.         else
  2711. # ifdef FEAT_FOLDING
  2712.         if (hasAnyFolding(curwin))
  2713.         {
  2714.         while (--n >= 0 && curwin->w_cursor.lnum > 1)
  2715.         {
  2716.             --curwin->w_cursor.lnum;
  2717.             (void)hasFolding(curwin->w_cursor.lnum,
  2718.                         &curwin->w_cursor.lnum, NULL);
  2719.         }
  2720.         }
  2721.         else
  2722. # endif
  2723.         curwin->w_cursor.lnum -= n;
  2724.     }
  2725. #else
  2726.     /* try to put the cursor in the same screen line */
  2727.     scrolled += n;        /* move cursor when topline is 1 */
  2728.     while (curwin->w_cursor.lnum > curwin->w_topline
  2729.           && (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
  2730.     {
  2731.         scrolled -= plines(curwin->w_cursor.lnum - 1);
  2732.         if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
  2733.         break;
  2734.         --curwin->w_cursor.lnum;
  2735. # ifdef FEAT_FOLDING
  2736.         foldAdjustCursor();
  2737. # endif
  2738.     }
  2739. #endif
  2740.     }
  2741. # ifdef FEAT_FOLDING
  2742.     /* Move cursor to first line of closed fold. */
  2743.     foldAdjustCursor();
  2744. # endif
  2745. #ifdef FEAT_DIFF
  2746.     check_topfill(curwin, !flag);
  2747. #endif
  2748.     cursor_correct();
  2749.     beginline(BL_SOL | BL_FIX);
  2750.     redraw_later(VALID);
  2751. }
  2752.